package com.example.util;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.db.CommonData;
import com.example.im.LoginActivity;
import com.example.im.MainActivity;
import com.example.model.Friends;
import com.example.model.Msg;
import com.example.model.User;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;

import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import static com.example.db.CommonData.commonData;
import static com.example.db.CommonData.getDbMsg;
import static com.example.db.CommonData.writeData;

public class MyUtil implements Serializable {
    public static MyUtil myUtil =new MyUtil();

    private static boolean login(Context context, String userName, String password) {
        try {
            Map<String, String> param = new HashMap<>();
            param.put("account", userName);
            param.put("password", password);
            MyUtil.Res res = MyUtil.postReqParam("/user/login", param);

            if (res != null) {
                //登录成功
                if (res.getCode() == 200) {
                    User loginUser = new User();
                    JSONObject d = res.getDataObject();
                    loginUser.setId(d.getInteger("id"));
                    loginUser.setName(d.getString("username"));
                    loginUser.setLoginIp(d.getString("loginIp"));
                    //调用接口获取所有用户信息
                    //将当前用户信息存入数据中
                    commonData.setToken(d.getString("accessToken"));
                    //将获取的好友信息和消息信息存入commondata中
                    commonData.setLogin(true);
                    commonData.setUser(loginUser);
                    // 保存
                    CommonData.writeData(context);
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static void exeUrlTask(Context context, Supplier<Res> reqFun, Consumer<Res> successfulFun) {
        exeUrlTask(context, reqFun, successfulFun, r -> toast(context, r.getCode()+r.getMessage()));
    }

    public static void exeUrlTask(Context context, Supplier<Res> reqFun,
                                  Consumer<Res> successfulFun,
                                  Consumer<Res> failureFun) {
        exeUrlTask(context, reqFun, successfulFun, failureFun, true);
    }

    public static void exeUrlTask(Context context, Supplier<Res> reqFun,
                                  Consumer<Res> successfulFun,
                                  Consumer<Res> failureFun, boolean async) {
        Runnable task = () -> {
            Res res = reqFun.get();
            Runnable postRun = null;
            if (res == null) {
                postRun = () -> toast(context, "网络异常");
            } else if (res.getCode() == 300) {
                // 未登录，或者登录过期，尝试重新登录
                User loginUser = commonData.getUser();
                if (loginUser == null || null == loginUser.getName() || null == loginUser.getPassword()) {
                    // 未登录提示
                    postRun = () -> toast(context, "未登录");
                    commonData.setLogin(false);
                    commonData.setUser(null);
                    commonData.setToken(null);
                    MyUtil.changeActivity((Activity) context, LoginActivity.class);
                } else {
                    // 登录过期，尝试重新登录
                    boolean isLogin = login(context, loginUser.getName(), loginUser.getPassword());
                    if (!isLogin) {
                        // 重新登录失败
                        postRun = () -> toast(context, "断开连接，重新登录失败");
                    } else {
                        // 登录成功，重新执行该方法 (同步执行)
                        exeUrlTask(context, reqFun, successfulFun, failureFun, false);
                        postRun = () -> toast(context, "登录已过期，重新登录成功");
                    }
                }
            } else if (res.getCode() != 200) {
                postRun = () -> failureFun.accept(res);
            } else {
                postRun = () -> successfulFun.accept(res);
            }

            if (null != postRun) {
                ((Activity) context).runOnUiThread(postRun);
            }
        };
        if (async) {
            MyUtil.exeTask(task);
        } else {
            task.run();
        }
    }
    public static Map<String, String> paramMap(List<String> keys, List<Object> values) {
        HashMap<String, String> map = new HashMap<>(keys.size());
        for (int i = 0; i < keys.size() && i < values.size(); i++) {
            String key = keys.get(i);
            String value = values.get(i) == null ? null : values.get(i).toString();
            map.put(key, value);
        }
        return map;
    }


    public static void initFirstMsg(String fName,int fid,Context context) {
        if(getDbMsg(commonData.getUser().getName(), fName).size()==0){
            //发送消息接口
            Msg sendMsg = new Msg();
            sendMsg.setSendTime(new Date());
            sendMsg.setMsg("我们已经是好友了，快来聊天吧");
            sendMsg.setUid(commonData.getUser().getId());
            sendMsg.setFid(fid);
            sendMsg.setMid(new Random().nextInt());
            sendMsg.setType(0);
            sendMsg.setStatus(false);
            HashMap<String, Object> param = new HashMap<>();
            param.put("content", sendMsg.getMsg());
            param.put("friendId", sendMsg.getFid());
            MyUtil.exeUrlTask(
                    context,
                    () -> MyUtil.postReqParam("/imChatUserMessage/sendFriendMessage", param),
                    (res) -> {
                        JSONObject msg_data = res.getDataObject();
                        sendMsg.setStatus(false);
                        sendMsg.setMsg(msg_data.getString("content"));
                        // 服务器消息0
                        sendMsg.setType(0);
                        sendMsg.setMid(msg_data.getInteger("id"));
                        sendMsg.setUid(msg_data.getInteger("fromId"));
                        sendMsg.setFid(msg_data.getInteger("toId"));

                        // 2.本地数据处理
                        CommonData.addDbMsg(commonData.getLoginUserName(), fName, sendMsg);
                    }
            );
        }
    }


    //处理json
    private String getStringByStream(InputStream inputStream){
        Reader reader;
        try {
            reader=new InputStreamReader(inputStream,"UTF-8");
            char[] rawBuffer=new char[512];
            StringBuffer buffer=new StringBuffer();
            int length;
            while ((length=reader.read(rawBuffer))!=-1){
                buffer.append(rawBuffer,0,length);
            }
            return buffer.toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void finishChangeActivity(Activity context, Class<?> targetActivityClass) {
        changeActivity(context, targetActivityClass, true);
    }
    public static void changeActivity(Activity context, Class<?> targetActivityClass) {
        changeActivity(context, targetActivityClass, false);
    }
    public static void changeActivity(Context context, Class<?> targetActivityClass, boolean isFinish) {
        Intent intent = new Intent(context, targetActivityClass);
        if (isFinish) {
            ((Activity) context).finish();
        }
        writeData(context);
        context.startActivity(intent);
    }

    public static void toast(Context context, String text) {
        Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
    }

    public static class Res {
        private int code;
        private String message;
        private JSON data;

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getMessage() {
            return message == null ? "" : message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public JSON getData() {
            return data;
        }

        public JSONObject getDataObject() {
            return (JSONObject) data;
        }

        public JSONArray getDataArray() {
            return (JSONArray) data;
        }

        public void setData(JSON data) {
            this.data = data;
        }

        public Res() {
        }

        public Res(int code, String message, JSON data) {
            this.code = code;
            this.message = message;
            this.data = data;
        }

        @Override
        public String toString() {
            return "Res{" +
                    "code=" + code +
                    ", message='" + message + '\'' +
                    ", data=" + data +
                    '}';
        }
    }

    /**
     * 发送get请求
     *
     * @param url    地址
     * @param params 参数
     * @return 请求结果
     */
    private static String get(String url, Map<String, ?> params) {
        return request("GET", url, params);
    }

    /**
     * 发送post请求
     *
     * @param url    地址
     * @param params 参数
     * @return 请求结果
     */
    private static String post(String url, Map<String, ?> params) {
        return request("POST", url, params);
    }

    public static String getUrl(String url) {
        return "http://1.15.72.167:8081" + url;
    }

    /**
     * 发送http请求
     *
     * @param method 请求方法
     * @param url    地址
     * @param params 参数
     * @return 请求结果
     */
    private static String request(String method, String url, Map<String, ?> params) {
        if (method == null) {
            throw new RuntimeException("请求方法不能为空");
        }

        if (url == null) {
            throw new RuntimeException("url不能为空");
        }

        HttpUrl.Builder httpBuilder = HttpUrl.parse(getUrl(url)).newBuilder();

        if (params != null) {
            for (Map.Entry<String, ?> param : params.entrySet()) {
                if (param.getValue() == null) {
                    continue;
                }
                try {
//                    httpBuilder.addQueryParameter(param.getKey(), URLEncoder.encode(param.getValue().toString(), "UTF-8"));
                    httpBuilder.addQueryParameter(param.getKey(), param.getValue().toString());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        Request request = null;
        try {
            HttpUrl build = httpBuilder.build();
            request = new Request.Builder()
                    .url(build)
                    .header("Authorization", commonData.getToken())
                    .method(method,
                            ("GET".equals(method) || "HEAD".equals(method)) ?
                                    null : new FormBody.Builder().build())
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        try {
            OkHttpClient client = new OkHttpClient.Builder()
                    .readTimeout(20, TimeUnit.SECONDS)
                    .build();
            Response response = client.newCall(request).execute();
            return response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 发送post请求（json格式）
     *
     * @param url  url
     * @param json json字符串
     * @return 请求结果
     */
    public static String postJson(String url, String json) {
        try {
            Request request = new Request.Builder()
                    .url(getUrl(url))
                    .header("Authorization", commonData.getToken())
                    .post(RequestBody.Companion.create(json, MediaType.Companion.parse("application/json")))
                    .build();
            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            return response.body().string();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 以post方式调用接口(入参格式为json)
     * @param url
     * @param reqObj
     * @return
     */
    public static Res postReqJson(String url, Object reqObj) {
        return req(postJson(url, JSON.toJSONString(reqObj == null ? new HashMap<>() : reqObj)));
    }



    /**
     * 以get方式调用接口
     * @param url
     * @param map
     * @return
     */
    public static Res getReqParam(String url, Map<String, ?> map) {
        return req(request("GET", url, map));
    }

    /**
     * 以post方式调用接口
     * @param url
     * @param map
     * @return
     */
    public static Res postReqParam(String url, Map<String, ?> map) {
        return req(request("POST", url, map));
    }

    private static Res req(String response) {
        try {
            JSONObject resJson = JSON.parseObject(response);
            String msg = resJson.getString("message");
            int code = resJson.getInteger("code");
            JSON data = (JSON) resJson.get("data");
            Res res = new Res(code, msg, data);
            Log.d("相应内容:", res.toString());
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Thread exeTask(Runnable task) {
        Thread thread = new Thread(task);
        thread.start();
        return thread;
    }


}
